Sort feature lists for fingerprint hashing
authorAlex Crichton <alex@alexcrichton.com>
Mon, 6 Oct 2014 03:21:57 +0000 (20:21 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Mon, 6 Oct 2014 03:23:18 +0000 (20:23 -0700)
Otherwise the order was nondeterministic likely due to some hash map along the
way being used to deduplicate the set of features.

Closes #665

src/cargo/ops/cargo_rustc/fingerprint.rs
tests/test_cargo_features.rs

index f1840da877dbf52e6d90b417c6876ffa46aa6311..6e7cff5f8efa466980d647769ce4a442e1fa9967 100644 (file)
@@ -61,7 +61,7 @@ pub fn prepare_target(cx: &mut Context, pkg: &Package, target: &Target,
         doc || !path
     };
 
-    debug!("fingerprint at: {}", new_loc.display());
+    info!("fingerprint at: {}", new_loc.display());
 
     // First bit of the freshness calculation, whether the dep-info file
     // indicates that the target is fresh.
@@ -72,7 +72,11 @@ pub fn prepare_target(cx: &mut Context, pkg: &Package, target: &Target,
     // Second bit of the freshness calculation, whether rustc itself, the
     // target are fresh, and the enabled set of features are all fresh.
     let features = cx.resolve.features(pkg.get_package_id());
-    let features = features.map(|s| s.iter().collect::<Vec<&String>>());
+    let features = features.map(|s| {
+        let mut v = s.iter().collect::<Vec<&String>>();
+        v.sort();
+        v
+    });
     let rustc_fingerprint = if use_pkg {
         mk_fingerprint(cx, &(target, try!(calculate_pkg_fingerprint(cx, pkg)),
                              features))
@@ -144,7 +148,7 @@ pub fn prepare_build_cmd(cx: &mut Context, pkg: &Package)
     let old_loc = old.join("build");
     let new_loc = new.join("build");
 
-    debug!("fingerprint at: {}", new_loc.display());
+    info!("fingerprint at: {}", new_loc.display());
 
     let new_fingerprint = try!(calculate_build_cmd_fingerprint(cx, pkg));
     let new_fingerprint = mk_fingerprint(cx, &new_fingerprint);
@@ -244,10 +248,10 @@ fn calculate_target_fresh(pkg: &Package, dep_info: &Path) -> CargoResult<bool> {
         match fs::stat(&pkg.get_root().join(file)) {
             Ok(stat) if stat.modified <= mtime => {}
             Ok(stat) => {
-                debug!("stale: {} -- {} vs {}", file, stat.modified, mtime);
+                info!("stale: {} -- {} vs {}", file, stat.modified, mtime);
                 return Ok(false)
             }
-            _ => { debug!("stale: {} -- missing", file); return Ok(false) }
+            _ => { info!("stale: {} -- missing", file); return Ok(false) }
         }
     }
 
index 2f6f4d2ad1bbb530e025bf69decb9cf58f9cef59..bad8fee8ea85042a9c83d4753d08a8526a9f19ed 100644 (file)
@@ -1,5 +1,6 @@
 use support::{project, execs, cargo_dir};
 use support::COMPILING;
+use support::paths::PathExt;
 use hamcrest::assert_that;
 
 fn setup() {
@@ -424,3 +425,40 @@ test!(union_features {
 {compiling} foo v0.0.1 ({dir})
 ", compiling = COMPILING, dir = p.url()).as_slice()));
 })
+
+test!(many_features_no_rebuilds {
+    let p = project("foo")
+        .file("Cargo.toml", r#"
+            [package]
+            name    = "b"
+            version = "0.1.0"
+            authors = []
+
+            [dependencies.a]
+            path = "a"
+            features = ["fall"]
+        "#)
+        .file("src/main.rs", "fn main() {}")
+        .file("a/Cargo.toml", r#"
+            [package]
+            name    = "a"
+            version = "0.1.0"
+            authors = []
+
+            [features]
+            ftest  = []
+            ftest2 = []
+            fall   = ["ftest", "ftest2"]
+        "#)
+        .file("a/src/lib.rs", "");
+
+    assert_that(p.cargo_process("build"),
+                execs().with_status(0).with_stdout(format!("\
+{compiling} a v0.1.0 ({dir})
+{compiling} b v0.1.0 ({dir})
+", compiling = COMPILING, dir = p.url()).as_slice()));
+    p.root().move_into_the_past().unwrap();
+
+    assert_that(p.process(cargo_dir().join("cargo")).arg("build"),
+                execs().with_status(0).with_stdout(""));
+})